/*
 *  Copyright 2009 Advanced Industrial Science and Technology (AIST).
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

/*! \file
 *  \brief
 */
#pragma once

// thrust, includes
#include <thrust/config/suffix.hpp>
#include <thrust/mpl/bool.hpp>

namespace thrust {
  
  struct no_property {
    typedef no_property tag_type;
    typedef no_property next_type;
    typedef no_property value_type;
    enum { num =0};
    typedef void kind;
  };

  
  template <class Tag, class T, class Base =no_property>
  struct property : public Base {
    typedef Base next_type;
    typedef Tag  tag_type;
    typedef T    value_type;
    
    property() : m_value() {}
    property( const T& v) : m_value(v) {}
    property( const T& v, const Base& b) : Base(b), m_value(v) {}
    
    T m_value;
  };
  
  template <class PropertyTag>
  struct property_kind {
    typedef typename PropertyTag::kind type;
  };
  
  template <class P>
  struct has_property : thrust::mpl::true_ {};
  template <>
  struct has_property<no_property> : thrust::mpl::false_ {};

} // namespace thrust

#include <thrust/pending/detail/property.hpp>

namespace thrust {
  
  template <class PropertyList, class Tag>
  struct property_value {
    typedef typename detail::build_property_tag_value_alist<PropertyList>::type AList;
    typedef typename detail::extract_value<AList,Tag>::type type;
  };
  
  template <class Tag2>
  __host__ __device__
  inline detail::error_property_not_found
  get_property_value( const no_property& p, Tag2) {
    return detail::error_property_not_found();
  }
  
  template <class Tag1, class Tag2, class T1, class Base>
  __host__ __device__
  inline typename property_value<property<Tag1,T1,Base>,Tag2>::type&
  get_property_value( property<Tag1,T1,Base>& p, Tag2 tag2) {
    
    THRUST_STATIC_CONSTANT( bool,
			    match = (detail::same_property<Tag1,Tag2>::value));
    
    typedef property<Tag1,T1,Base> Prop;
    typedef typename property_value<Prop,Tag2>::type T2;
    
    T2* t2 =0;
    typedef detail::property_value_dispatch<match> Dispatcher;
    return Dispatcher::get_value( p, t2, tag2);
  }
  
  /*template <class Tag1, class Tag2, class T1, class Base>
  __host__ __device__
  inline const typename property_value<property<Tag1,T1,Base>,Tag2>::type&
  get_property_value( const property<Tag1,T1,Base>& p, Tag2 tag2) {
    
    THRUST_STATIC_CONSTANT( bool,
			    match = (detail::same_property<Tag1,Tag2>::value));

    typedef property<Tag1,T1,Base> Prop;
    typedef typename property_value<Prop,Tag2>::type T2;
    
    T2* t2 =0;
    typedef detail::property_value_dispatch<match> Dispatcher;
    return Dispatcher::const_get_value( p, t2, tag2);
    }*/

} // namespace thrust
